import { mapboxgl } from '@mapgis/mapbox-gl';
import { Common } from '@mapgis/webclient-es6-service';

const { extend, Zondy } = Common;

/**
 * @class Theme3DLayer
 * @classdesc 三维专题图基类,不能直接实例化
 * @param  id -{string} 专题图图层id
 * @param  layerOptions -{Object} 专题图图层配置项<br>
 *             opacity -{number} 图层透明度，默认1<br>
 *             parseNumber -{boolean} 是否预处理数据，将数据转换为number，默认false<br>
 *             enableHighlight -{boolean} 是否开启高亮,默认false<br>
 *             highlight -{Object} 高亮颜色,默认"#ADA91E"<br>
 *             baseHeightField -{string} 数据中表示基础高度的字段<br>
 *             height -{number} 高度。如果数据指定的heightField(默认height)没有可以表示高度的字段，可以为所有数据统一设置一个高度<br>
 *             heightField -{string} 数据中表示高度的字段<br>
 *             themeField -{string} 专题展示的字段<br>
 *             showLegend -{boolean} 是否显示图例,默认显示<br>
 *             legendTitle -{string} 图例标题<br>
 *             legendTheme -{string} 图例主题，取值：'light','dark',默认：'light'<br>
 *             legendOrientation -{string} 图例方向，取值：'horizontal','vertical'，默认：'horizontal'<br>
 *             legendPosition -{string} 图例位置，取值：'top-right'|'top-left'|'bottom-left'|'bottom-right'<br>
 */
class Theme3DLayer {
    constructor(id, layerOptions) {
        /**
         * @member  id -{string}
         * @description mapbox gl图层id
         */
        this.id = id;

        /**
         * @member  map -{object}
         * @description mapbox gl地图对象
         */
        this.map = null;
        /**
         * @member  opacity -{number}
         * @description 图层透明度，默认1
         */
        this.opacity = 1;
        /**
         * @member  parseNumber -{boolean}
         * @description 是否进行数据预处理,有些字段是string类型，需要转换为number
         */
        this.parseNumber = false;
        /**
         * @member  enableHighlight -{boolean}
         * @description 是否开启高亮,默认false
         */
        this.enableHighlight = false;

        /**
         * @member  highlight -{Object}
         * @description 高亮相关配置,默认null
         */
        this.highlight = { color: '#ADA91E' };

        /**
         * @member  baseHeightField -{string}
         * @description 数据中表示基础高度的字段
         */
        this.baseHeightField = null;

        /**
         * @member height -{number}
         * @description 高度。如果数据指定的heightField(默认height)没有可以表示高度的字段，可以为所有数据统一设置一个高度
         */
        this.height = null;

        /**
         * @member  heightField -{string}
         * @description 数据中表示高度的字段
         */
        this.heightField = 'height';

        /**
         * @member  themeField -{string}
         * @description 专题展示的字段
         */
        this.themeField = this.heightField;

        /**
         * @member  showLegend -{Boolean}
         * @description 是否显示图例
         */
        this.showLegend = true;

        /**
         * @member  legendTitle -{string}
         * @description 图例标题
         */
        this.legendTitle = null;

        /**
         * @member  legendTheme -{string}
         * @description 图例主题，取值：'light','dark'
         * @default 'light'
         */
        this.legendTheme = 'light';

        /**
         * @member  legendOrientation -{string}
         * @description 图例方向，取值：'horizontal','vertical'，默认：'horizontal'
         * @default 'horizontal'
         */
        this.legendOrientation = 'horizontal';
        /**
         * @member  legendPosition -{string}
         * @description 图例位置，取值：'top-right'|'top-left'|'bottom-left'|'bottom-right'
         * @default 'bottom-right'
         */
        this.legendPosition = 'bottom-right';
        this.mousemoveOn = true;
        extend(this, layerOptions);
    }

    /**
     * @function setLayerOptions
     * @description 设置图层相关参数
     * @param layerOptions -{object} 该专题图图层相关参数<br>
     * *          opacity -{number} 图层透明度，默认1<br>
     *            parseNumber -{boolean} 是否预处理数据，将数据转换为number，默认false<br>
     *            baseHeightField -{string} 数据中表示基础高度的字段<br>
     *            height -{number} 高度。如果数据指定的heightField(默认height)没有可以表示高度的字段，可以为所有数据统一设置一个高度<br>
     *            heightField -{string} 数据中表示高度的字段<br>
     *            themeField -{string} 专题展示的字段<br>
     *            showLegend -{boolean} 是否显示图例,默认显示<br>
     *            legendTitle -{string} 图例标题<br>
     *            legendTheme -{string} 图例主题，取值：'light','dark',默认：'light'<br>
     *            legendOrientation -{string} 图例方向，取值：'horizontal','vertical'，默认：'horizontal'<br>
     *            legendPosition -{string} 图例位置，取值：'top-right'|'top-left'|'bottom-left'|'bottom-right'<br>
     * @returns {this}
     */
    setLayerOptions(layerOptions) {
        extend(this, layerOptions);
        return this;
    }

    /**
     * @function mapboxgl.zondy.Theme3DLayer.prototype.setHighlightStyleOptions
     * @description 设置图层高亮相关参数
     * @param highlightOptions -{object} 该专题图图层高亮相关参数<br>
     *            color -{string} 颜色<br>
     *            callback -{function} 回调,返回数据参数（data,event）<br>
     * @returns {this}
     */
    setHighlightStyleOptions(highlightOptions) {
        extend(this.highlight, highlightOptions);
        return this;
    }

    /**
     * @function setData
     * @description 设置数据，数据格式必须为geojson格式
     * @param data -{object} geojson格式数据
     * @param parseNumber -{object} 是否进行数据预处理,有些字段是string类型，需要转换为number
     */
    setData(data, parseNumber) {
        var me = this;
        me.data = data;
        if (parseNumber != null) {
            me.parseNumber = parseNumber;
        }
        me.parseNumber &&
            me.data &&
            me.data.features &&
            me.data.features.map(function (val) {
                if (me.baseHeightField && val.properties[me.baseHeightField]) {
                    val.properties[me.baseHeightField] = parseFloat(val.properties[me.baseHeightField]);
                }
                if (me.heightField && val.properties[me.heightField]) {
                    val.properties[me.heightField] = parseFloat(val.properties[me.heightField]);
                }
                return val;
            });
        return this;
    }

    WebMercator2lonLat(cx, cy) {
        var x = (cx / 20037508.34) * 180;
        var y = (cy / 20037508.34) * 180;
        y = (180 / Math.PI) * (2 * Math.atan(Math.exp((y * Math.PI) / 180)) - Math.PI / 2);
        return [x, y];
    }

    convertData(data) {
        if (data != null && data.features != null && data.features.length > 0) {
            for (var i = 0; i < data.features.length; i++) {
                var temGeom = data.features[i].geometry;
                if (temGeom != null && temGeom.coordinates != null && temGeom.coordinates.length > 0) {
                    if (temGeom.type == 'Polygon') {
                        var rings = temGeom.coordinates;
                        for (var j = 0; j < rings.length; j++) {
                            var ring = rings[j];
                            if (ring != null && ring.length > 0) {
                                for (var k = 0; k < ring.length; k++) {
                                    let coordinate = new mapboxgl.LngLat(ring[k][0], ring[k][1]);
                                    let tempPoint = map.project(coordinate);
                                    data.features[i].geometry.coordinates[j][k] = [tempPoint.x, tempPoint.y];
                                }
                            }
                        }
                    } else if (temGeom.type == 'MultiPolygon') {
                        var polygons = temGeom.coordinates;
                        for (var m = 0; m < polygons.length; m++) {
                            var polygon = polygons[m];
                            if (polygon != null && polygon.length > 0) {
                                for (var j = 0; j < polygon.length; j++) {
                                    var ring = polygon[j];
                                    if (ring != null && ring.length > 0) {
                                        for (var k = 0; k < ring.length; k++) {
                                            let coordinate = new mapboxgl.LngLat(ring[k][0], ring[k][1]);
                                            let tempPoint = map.project(coordinate);
                                            data.features[i].geometry.coordinates[m][j][k] = [tempPoint.x, tempPoint.y];
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return data;
    }
    /**
     * @function getData
     * @description 获取数据，返回的数据格式为geojson
     * @returns {Object}
     */
    getData() {
        return this.data;
    }

    /**
     * @function addTo
     * @description 添加图层到地图上
     * @param map -{Object} mapboxgl 地图对象
     * @returns {this}
     */
    addTo(map) {
        this.map = map;
        if (!this.map) {
            return this;
        }

        this.show();
        return this;
    }

    /**
     * @function show
     * @description 显示图层
     * @param options -{Object} 图层配置项
     * @returns {this}
     */
    show(options) {
        extend(this, options);
        this._addLayer();
        if (this.enableHighlight) {
            this._addHighLightLayer();
        }
        if (this.showLegend) {
            if (!this.legend) {
                this.legend = this._createLegendControl();
            }
            this.map.addControl(this.legend, this.legendPosition);
        }
        return this;
    }

    /**
     * @function remove
     * @description 从地图上移除图层
     * @returns {this}
     */
    remove() {
        if (!this.map) {
            return this;
        }
        var me = this;
        me.mousemoveOn = false;
        // this.map.off('mousemove',function(e){
        //     me.mousemoveCallback(e,me);
        // });
        //移除图层
        var layerId = this.id ? this.id : 'theme3DLayer';
        if (this.map.getLayer(layerId)) {
            this.map.removeLayer(layerId);
        }
        //移除高亮图层
        var highlightLayerId = 'highlightLayer';
        if (this.map.getLayer(highlightLayerId)) {
            this.map.removeLayer(highlightLayerId);
        }
        // if (!!this.map.getSource(this.sourceId)) {
        //   this.map.removeSource(this.sourceId);
        // }
        // if (!!this.map.getSource("highlight")) {
        //   this.map.removeSource("highlight");
        // }

        //移除图例
        if (this.legend) {
            this.map.removeControl(this.legend);
        }

        return this;
    }

    /**
     * @function  getLayerStyleOptions
     * @description 获取图层样式
     * @return {Object} mapbox gl样式对象
     */
    getLayerStyleOptions() {
        //子类重写实现
    }

    /**
     * @function mapboxgl.zondy.Theme3DLayer.prototype.getHighlightStyleOptions
     * @description 获取高亮样式,子类重写实现
     * @returns {Object} mapbox gl样式对象
     */
    getHighlightStyleOptions() {
        //子类重写实现
    }

    _createLegendControl(html) {
        var me = this;

        function LegendControl() {}

        LegendControl.prototype.onAdd = function (map) {
            this._map = map;
            this._container = document.createElement('div');
            var className = 'mapboxgl-ctrl legend ';
            var theme = 'legend-light';
            if (me.legendTheme === 'dark') {
                theme = 'legend-dark';
            }
            var orientation = ' legend-horizontal';
            if (me.legendOrientation === 'vertical') {
                orientation = ' legend-vertical';
            }
            this._container.className = className + theme + orientation;

            if (html) {
                this._container.innerHTML = html;
            } else {
                var legendTitle = me.legendTitle || '';
                var titleElement = " <div class='legend-title'>" + legendTitle + '</div>';
                var content = me._createLegendElement.call(me) || '';
                var contentElement = "<div class='legend-content'>" + content + '</div>';
                this._container.innerHTML = titleElement + contentElement;
            }
            me._appendLegendCSSStyle();
            return this._container;
        };

        LegendControl.prototype.onRemove = function () {
            this._container.parentNode.removeChild(this._container);
            this._map = undefined;
        };

        return new LegendControl();
    }

    _createLegendElement() {
        //子类实现
    }

    _addLayer() {
        var paintOptions = this.getLayerStyleOptions();
        var id = this.id ? this.id : 'theme3DLayer';
        this.id = id;
        var sourceId = (this.sourceId = id + 'Source');
        if (!!this.map.getSource(sourceId)) {
            this.map.removeSource(sourceId);
        }
        this.map.addSource(sourceId, {
            type: 'geojson',
            data: this.data
        });
        if (!!this.map.getLayer(id)) {
            this.map.removeLayer(id);
        }
        this.map.addLayer({
            id: id,
            type: 'fill-extrusion',
            source: sourceId,
            paint: paintOptions
        });

        this.map.moveLayer(id);
    }

    //添加高亮图层
    _addHighLightLayer() {
        if (!this.map) {
            return;
        }
        var map = this.map;
        if (map.getSource('highlight')) {
            map.removeSource('highlight');
        }
        map.addSource('highlight', {
            type: 'geojson',
            data: {
                type: 'FeatureCollection',
                features: []
            }
        });
        if (!!map.getLayer('highlightLayer')) {
            map.removeLayer('highlightLayer');
        }
        map.addLayer({
            id: 'highlightLayer',
            type: 'fill-extrusion',
            source: 'highlight',
            paint: this.getHighlightStyleOptions()
        });

        var me = this;
        var featureId;
        //map.on('mousemove',this.mousemoveCallback);
        // map.on('mousemove',function(e){
        //     if(!me.mousemoveOn)
        //     {
        //         return;
        //     }
        //     me.mousemoveCallback(e,me);
        // });

        map.on('mousemove', function (e) {
            if (!me.mousemoveOn) {
                return;
            }
            me.mousemoveOn = true;
            var canvas = document.querySelector('.mapboxgl-canvas-container.mapboxgl-interactive');
            canvas.style.cursor = 'auto';

            var features = me.map.queryRenderedFeatures(e.point, { layers: [me.id] });
            //var sta =  me.map.getFeatureState(features[0]);

            if (me.highlight && me.highlight.callback) {
                me.highlight.callback(features, e);
            }

            if (!features || features.length < 1) {
                me._clearHighlight.call(me);
                return;
            }
            var id = features[0].properties.fid;
            if (featureId === id) {
                return;
            }
            featureId = id;
            me._clearHighlight.call(me);
            var sourceFeatures = me.map.querySourceFeatures(me.sourceId, {
                filter: ['==', 'fid', id]
            });
            var i,
                len = sourceFeatures.length;
            var geoFeatures = { type: 'FeatureCollection', features: [] };
            for (i = 0; i < len; i++) {
                geoFeatures['features'].push(sourceFeatures[i].toJSON());
            }
            me.map.getSource('highlight').setData(geoFeatures);
        });
    }
    // mousemoveCallback (e,obj) {
    //         obj.mousemoveOn= true;
    //         var canvas = document.querySelector('.mapboxgl-canvas-container.mapboxgl-interactive');
    //         canvas.style.cursor = 'auto';

    //         var features = obj.map.queryRenderedFeatures(e.point, {layers: [obj.id]});
    //         if (obj.highlight && obj.highlight.callback) {
    //             obj.highlight.callback(features, e);
    //         }

    //         if (!features || features.length < 1) {
    //             obj._clearHighlight.call(obj);
    //             return;
    //         }
    //         var id = features[0].properties.fid;
    //         if (featureId === id) {
    //             return;
    //         }
    //         featureId = id;
    //         obj._clearHighlight.call(obj);
    //         var sourceFeatures = obj.map.querySourceFeatures(obj.sourceId, {filter: ['==','fid',id]});
    //         var i, len = sourceFeatures.length;
    //         var geoFeatures = {'type': 'FeatureCollection', 'features': []};
    //         for (i = 0; i < len; i++) {
    //             geoFeatures['features'].push(sourceFeatures[i].toJSON());
    //         }
    //         obj.map.getSource('highlight').setData(geoFeatures);
    //     }
    _clearHighlight() {
        if (this.map) {
            if (!!this.map.getSource('highlight')) {
                this.map.getSource('highlight').setData({
                    type: 'FeatureCollection',
                    features: []
                });
            }
        }
    }

    _appendLegendCSSStyle() {
        var legendStyle = document.createElement('style');
        legendStyle.type = 'text/css';
        var baseStyle = `
        .legend {
            display: inline-block;
            border-radius: 2px;
            -moz-border-radius: 2px;
            -webkit-border-radius: 2px;
            font-size: 12px;
            color: rgba(0, 0, 0, 0.8);
            background-color: rgb(255, 255, 255);
        }
        .legend-light {
            color: rgba(0, 0, 0, 0.8);
            background-color: rgb(255, 255, 255);
            box-shadow: 0px 0px 6px #bbbbbb;
            -moz-box-shadow: 0px 6px 10px #bbbbbb;
            -webkit-box-shadow: 0px 0px 6px #bbbbbb;
        }
        .legend-dark {
            color: rgba(255, 255, 255, 0.8);
            background-color: rgb(64, 64, 64);
        }
        .legend .legend-title {
            min-height: 14px;
            max-width: 500px;
            padding:6px 10px;
        }
        .legend-light .legend-title {
            color: rgba(0, 0, 0, 0.8);
        }
        .legend-dark .legend-title {
            color: rgba(255, 255, 255, 0.8);
        }
        .legend-content{
            padding:6px 10px;
        }
        `;
        legendStyle.innerHTML = baseStyle + this._legendCSSStyle();
        document.getElementsByTagName('head')[0].appendChild(legendStyle);
    }

    //各种图层对应的自己的图例的样式
    _legendCSSStyle() {
        //子类可重写实现
        return `  
        .legend ul {
            padding: 0;
            margin: 0 16px;
            height: 100%;
            display: block;
            list-style: none;
        }

        .legend li {
            vertical-align: middle;
        }

        .legend li span:first-child {
            vertical-align: middle;
        }

        .legend li span:last-child {
            line-height: 28px;
            max-width: 200px;
            vertical-align: middle;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            -ms-text-overflow: ellipsis;
        }

        .legend-vertical li {
            height: 28px;
        }

        .legend-vertical li span:first-child {
            display: inline-block;
            width: 60px;
            height: 100%;
        }

        .legend-vertical li span:last-child {
            display: inline-block;
            margin-left: 16px;
            height: 100%;
        }

        .legend-horizontal li {
            height: 56px;
            float: left;
        }

        .legend-horizontal li span:first-child {
            display: block;
            width: 100%;
            height: 50%;
        }

        .legend-horizontal li span:last-child {
            display: block;
            vertical-align: middle;
            width: 60px;
            height: 50%;
            text-align: center;
        }
        `;
    }
}
export { Theme3DLayer };
Zondy.Map.Theme3DLayer = Theme3DLayer;
